package prv.pursuivant.unimportant.scraps;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.TreeSet;
import java.util.Vector;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

/**
 * Absolutely not important piece of code for first draft - just to translate
 * achievements trees
 * 
 * @author Kwinto
 * 
 */

public class OldAchiev implements Comparable<OldAchiev> {

	public OldAchiev(String id, String name, Boolean active) {
		this.id = id; // = "2137"
		this.name = name; // = "Glory of the Raider"
	}

	public OldAchiev(String id, String name) {
		this(id, name, false);
	}

	@Override
	public String toString() {
		return name + "/" + id + "/" + criteria;
	}

	public final String id;
	public final String name;
	public String link;
	public Vector<OldAchiev> criteria = null;
	private final int index = counter++;
	public Boolean active;
	private static int counter = 0;

	public void exportData() throws IOException {
		// sort
		sort();
		FileOutputStream fos = new FileOutputStream(getResourceName("" + id));
		XStream xstream = makeXStream();
		xstream.toXML(this, fos);
		fos.close();
	}

	private void sort() {
		Queue<OldAchiev> toSort = new LinkedList<OldAchiev>();
		toSort.add(this);
		while (!toSort.isEmpty()) {
			OldAchiev a = toSort.remove();
			if (null != a.criteria) {
				toSort.addAll(a.criteria);
				TreeSet<OldAchiev> sorted = new TreeSet<OldAchiev>(
						new AchievementComparator());
				sorted.addAll(a.criteria);
				a.criteria.clear();
				a.criteria.addAll(sorted);
			}
		}
	}

	public static OldAchiev importData(String categoryId) throws IOException {
		FileInputStream fis = new FileInputStream(getResourceName(categoryId));
		XStream xstream = makeXStream();
		Object fromXML = xstream.fromXML(fis);
		final OldAchiev achiev = (OldAchiev) fromXML;
		return achiev;
	}

	private static String getResourceName(String categoryId) {
		return "oldData/category." + categoryId + ".xml";
	}

	private static XStream makeXStream() {
		XStream xstream = new XStream(new DomDriver());
		xstream.alias("achievement", OldAchiev.class);
		xstream.omitField(OldAchiev.class, "index");
		xstream.useAttributeFor(String.class);
		xstream.useAttributeFor(Integer.class);
		xstream.useAttributeFor(Boolean.class);
		return xstream;
	}

	public OldAchiev getAchievByName(String name, boolean recursive) {
		if (name.equals(this.name))
			return this;
		if (criteria == null)
			return null;
		if (recursive) {
			Queue<OldAchiev> toSearch = new LinkedList<OldAchiev>();
			toSearch.add(this);
			while (!toSearch.isEmpty()) {
				final Vector<OldAchiev> children = toSearch.remove().criteria;
				if (children != null)
					for (OldAchiev child : children)
						if (name.equals(child.name))
							return child;
						else
							toSearch.add(child);
			}
		} else {
			for (OldAchiev child : criteria)
				if (name.equals(child.name))
					return child;
		}
		return null;
	}

	public OldAchiev getAchievById(Integer id, boolean recursive) {
		if (id.equals(this.id))
			return this;
		if (criteria == null)
			return null;
		if (recursive) {
			Queue<OldAchiev> toSearch = new LinkedList<OldAchiev>();
			toSearch.add(this);
			while (!toSearch.isEmpty()) {
				final Vector<OldAchiev> children = toSearch.remove().criteria;
				if (children != null)
					for (OldAchiev child : children)
						if (id.equals(child.id))
							return child;
						else
							toSearch.add(child);
			}
		} else {
			for (OldAchiev child : criteria)
				if (id.equals(child.id))
					return child;
		}
		return null;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj instanceof OldAchiev) {
			OldAchiev o = (OldAchiev) obj;
			// TODO: moze wystarczy return this.name.equals(o.name); ?
			if (this.id == null)
				if (o.id == null)
					return o.name.equals(this.name);
				else
					return false;
			else if (o.id == null)
				return false;
			else
				return this.id.equals(o.id);
		} else
			return false;
	}

	@Override
	public int hashCode() {
		return name.hashCode() * (id == null ? 1 : id.hashCode());
	}

	@Override
	public int compareTo(OldAchiev o) {
		if (this == o)
			return 0;
		else if (getAchievByName(o.name, true) != null)
			return 1;
		else if (o.getAchievByName(name, true) != null)
			return -1;
		else if (id == null || o.id == null)
			return index - o.index;
		else
			return id.compareTo(id);
	}

	private final class AchievementComparator implements Comparator<OldAchiev> {
		@Override
		public int compare(OldAchiev o1, OldAchiev o2) {
			if (o1 == o2)
				return 0;
			if (o1.id == null || o2.id == null)
				return o1.index - o2.index;
			return o1.id.compareTo(o2.id);
		}
	}

}
